// test_baseobject.h
#ifndef __BASEOBJECT_TEST_H
#define __BASEOBJECT_TEST_H

#include "common.h"

#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/config/SourcePrefix.h>

class BaseObjectTest : public CPPUNIT_NS::TestFixture
{
	CPPUNIT_TEST_SUITE( BaseObjectTest );
	CPPUNIT_TEST( test_object_create );
	CPPUNIT_TEST( test_Point );
	CPPUNIT_TEST( test_Candidate );
	CPPUNIT_TEST( test_Cell );
	CPPUNIT_TEST( test_CellSet );
	CPPUNIT_TEST( test_Puzzle );
	CPPUNIT_TEST_SUITE_END();

public:
	void setUp()
	{
	}

	void tearDown()
	{
	}

	void test_object_create()
	{
		cout << "test Create All BaseObject Instance..." << endl;
		Point p(1,1);
		Candidate cand(9);
		Cell cell(p);
        CellSet cs(CellSet_X,1);
		//Puzzle pz;
		dlx_solver ds ;
		generator gen;
	}

	void test_Point()
	{
		cout << "test Interface of Point ..." << endl;
		Point p;
		CPPUNIT_ASSERT(p.getX()==0);
		CPPUNIT_ASSERT(p.getY()==0);
		p.setX(1);
		p.setY(1);
		CPPUNIT_ASSERT(p.getX()==1);
		CPPUNIT_ASSERT(p.getY()==1);
		CPPUNIT_ASSERT(stricmp(p.toString(),"A1")==0);
		p.setX(9);
		p.setY(9);
		CPPUNIT_ASSERT(p.getX()==9);
		CPPUNIT_ASSERT(p.getY()==9);
		CPPUNIT_ASSERT(stricmp(p.toString(),"I9")==0);
		p.setXY(3,4);
		CPPUNIT_ASSERT(p.getX()==3);
		CPPUNIT_ASSERT(p.getY()==4);
		CPPUNIT_ASSERT(stricmp(p.toString(),"D3")==0);

		Point p2(p);
		CPPUNIT_ASSERT(p.isEqual(p2));
		CPPUNIT_ASSERT(p2.isEqual(p));

		Point p3;
		p3=p;
		CPPUNIT_ASSERT(p.isEqual(p3));
		CPPUNIT_ASSERT(p3.isEqual(p));

		bool bException=false;
		try{
			p.setX(0);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);

		bException=false;
		try{
			p.setY(0);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);
		bException=false;
		try{
			p.setX(10);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);

		bException=false;
		try{
			p.setY(10);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);
	}
	void test_Candidate()
	{
		cout << "test Interface of Candidate ..." << endl;
		Candidate cand(1);
		char tmp[20];
        sprintf(tmp,"%d[%d]",1,STA_NORMAL);
		CPPUNIT_ASSERT(stricmp(cand.toString(),tmp)==0);
        cand.setValue(STA_NONE);
        CPPUNIT_ASSERT(cand.getValue()==STA_NONE);
        cand.setValue(STA_NORMAL);
        CPPUNIT_ASSERT(cand.getValue()==STA_NORMAL);
        cand.setValue(STA_TAG);
        CPPUNIT_ASSERT(cand.getValue()==STA_TAG);
		bool bException=false;
		try
		{
			cand.setValue(10);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);

	}
	void test_Cell()
	{
		cout << "test Interface of Cell ..." << endl;
		Point p(1,1);
		Cell c(p);
		CPPUNIT_ASSERT(c.getNumber()==0);
		vector<ICandidate *> cands=c.getCandidates();
		CPPUNIT_ASSERT(cands.size()==9);
		for(vector<ICandidate *>::const_iterator itor=cands.begin();itor!=cands.end();++itor)
		{
            CPPUNIT_ASSERT((*itor)->getValue() == STA_NORMAL);
		}
        for(unsigned int i=LOWER_BOUNDER;i<=UPPER_BOUNDER;++i)
		{
			c.setNumber(0);
			c.setNumber(i);
			CPPUNIT_ASSERT(c.getNumber()==i);
		}
		c.setNumber(0);
        c.setNumber(LOWER_BOUNDER);
        c.setNumber(LOWER_BOUNDER+1);
        CPPUNIT_ASSERT(c.getNumber()==LOWER_BOUNDER);//Can't set cell value twice!

		c.setNumber(0);
		bool bException=false;
		try
		{
			c.setNumber(10);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);
	}
	void test_CellSet()
	{
		cout << "test Interface of CellSet ..." << endl;

		//Test xy2z static member function
		//vector<Point> pts=
		Point pts[]={	Point(1,1),Point(3,3),Point(4,1),Point(6,3),Point(7,1),Point(9,3),
			Point(1,4),Point(3,6),Point(4,4),Point(6,6),Point(7,4),Point(9,6),
			Point(1,7),Point(3,9),Point(4,7),Point(6,9),Point(7,7),Point(9,9)
		};
		for(int i=0;i<(int)(sizeof(pts)/sizeof(Point));++i)
		{
            //cout << pts[i].toString() << " -> " << CellSet::xy2z(pts[i]) << " vs " << (i/2+1) << endl;
            CPPUNIT_ASSERT(CellSet::xy2z(pts[i])==(i/2+1));
		}

        CellSet csy(CellSet_Y,1);
		CPPUNIT_ASSERT(stricmp("Row:A",csy.toString())==0);
        CellSet csz(CellSet_Z,2);
		CPPUNIT_ASSERT(stricmp("Box:2",csz.toString())==0);
        CellSet cs(CellSet_X,1);
		CPPUNIT_ASSERT(stricmp("Col:1",cs.toString())==0);
		Cell c(Point(1,1));
		cs.registerCell(&c);
		CPPUNIT_ASSERT(cs.getCells()[0]== &c);
		c.registerCellSet(&cs);
        CPPUNIT_ASSERT(c.getCellSets()[0]==&cs);

		Cell c2(Point(2,2));

		bool bException=false;
		try
		{
			cs.registerCell(&c2);
		}
		catch   (const   exception   &e)  
		{  
			cout   <<   e.what()   <<   endl;
			bException=true;
		}
		CPPUNIT_ASSERT(bException);	
	}
	void test_Puzzle()
	{
        cout << "test Interface of Puzzle ..." << endl;
        Puzzle pz;
        //getStatus()的缺省状态测试
        CPPUNIT_ASSERT(pz.getStatus()==PuzzleIsPlaying);
		string strempty="000000000000000000000000000000000000000000000000000000000000000000000000000000000";
        string strres=pz.exportPuzzle();
        CPPUNIT_ASSERT(strempty==strres);//exportPuzzle默认导出测试
        string strsudoku ="4.......5.2.....6...9...1..8..6.5..4.6..7..2.1..3.4..9..1...3...5.....8.7.......1";
		string strsudoku2="400000005020000060009000100800605004060070020100304009001000300050000080700000001";
		string strsudoku3="410000005020000060009000100800605004060070020100304009001000300050000080700000001";
		pz.loadPuzzle(strsudoku.c_str());

        //验证导出函数
        string strFormatNumber81=strsudoku2;
        string strFormatMultiLine="400000005\r\n020000060\r\n009000100\r\n800605004\r\n060070020\r\n100304009\r\n001000300\r\n050000080\r\n700000001\r\n";
        string strFormatSimpleTable="+---+---+---+\r\n"
                                    "|400|000|005|\r\n"
                                    "|020|000|060|\r\n"
                                    "|009|000|100|\r\n"
                                    "+---+---+---+\r\n"
                                    "|800|605|004|\r\n"
                                    "|060|070|020|\r\n"
                                    "|100|304|009|\r\n"
                                    "+---+---+---+\r\n"
                                    "|001|000|300|\r\n"
                                    "|050|000|080|\r\n"
                                    "|700|000|001|\r\n"
                                    "+---+---+---+\r\n";
        //缺省导出测试
        CPPUNIT_ASSERT(pz.exportPuzzle(FormatNumber81)==strFormatNumber81);
        //cout << endl << "===========" << endl << pz.exportPuzzle(FormatMultiLine) << endl <<  "===========" << endl<< strFormatMultiLine << endl << "===========" << endl;
        //多行格式导出测试（9x9）
        CPPUNIT_ASSERT(pz.exportPuzzle(FormatMultiLine)==strFormatMultiLine);
        cout << endl << pz.exportPuzzle(FormatMultiLine) << endl;
        //Ansi Simple Table格式导出测试
        cout << endl << pz.exportPuzzle(FormatSimpleTable) << endl;
        CPPUNIT_ASSERT(pz.exportPuzzle(FormatSimpleTable)==strFormatSimpleTable);

        cout << endl << pz.exportPuzzle(FormatFullTable) << endl;

        CPPUNIT_ASSERT(pz.getStatus()==PuzzleIsPlaying);
        //getNumber接口测试
        CPPUNIT_ASSERT(pz.getNumber(Point(1,1))==4);
        //缺省导出测试
		CPPUNIT_ASSERT(strsudoku2==string(pz.exportPuzzle()));
		pz.setNumber(Point(2,1),1);
        //setNumber测试（用getNumber组合校验）
		CPPUNIT_ASSERT(pz.getNumber(Point(2,1))==1);
		CPPUNIT_ASSERT(strsudoku3==string(pz.exportPuzzle()));
        //clear接口测试
		pz.clear();
		CPPUNIT_ASSERT(strempty==string(pz.exportPuzzle()));
        for(int y=LOWER_BOUNDER;y<=UPPER_BOUNDER;++y)
		{
            for(int x=LOWER_BOUNDER;x<=UPPER_BOUNDER;++x)
			{
				Point p(x,y);
				ICell *cp=pz.getCell(p);
				//cout << cp->getPoint()->toString() << "vs" << p.toString() << endl;
                //getCell接口测试
                CPPUNIT_ASSERT(cp->getPoint().isEqual(p));
			}
		}
        string strResult="417862935325917468689543172893625714564179823172384659241758396956431287738296541";
        Puzzle pzover;
        pzover.loadPuzzle(strResult.c_str());
        CPPUNIT_ASSERT(pzover.getStatus()==PuzzleIsOver);
        //还需要测试自动和手动解题的接口 (见test_logic.h:: test_Solver() )

        char pszEmpty[]=
                "┏━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┓\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃12345│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │6789 ┃\r\n"
                "┗━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┛\r\n";
        char pszNotEmpty[]=
                "┏━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┳━━━━━┯━━━━━┯━━━━━┓\r\n"
                "┃  1  │23456│23456┃23456│23456│23456┃23456│23456│23456┃\r\n"
                "┃     │789  │789  ┃789  │789  │789  ┃789  │789  │78   ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│23456│23456┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │789  │789  ┃6789 │6789 │6789 ┃6789 │6789 │678  ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│23456│23456┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │789  │789  ┃6789 │6789 │6789 ┃6789 │6789 │678  ┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │678  ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │678  ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │6789 │6789 ┃6789 │6789 │6789 ┃6789 │6789 │678  ┃\r\n"
                "┣━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━╋━━━━━┿━━━━━┿━━━━━┫\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │6789 │6789 ┃6789 │6789 │6789 ┃678  │678  │678  ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│12345┃\r\n"
                "┃789  │6789 │6789 ┃6789 │6789 │6789 ┃678  │678  │678  ┃\r\n"
                "┠─────┼─────┼─────╂─────┼─────┼─────╂─────┼─────┼─────┨\r\n"
                "┃23456│12345│12345┃12345│12345│12345┃12345│12345│  9  ┃\r\n"
                "┃78   │678  │678  ┃678  │678  │678  ┃678  │678  │     ┃\r\n"
                "┗━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┻━━━━━┷━━━━━┷━━━━━┛\r\n";

        Puzzle pzEmpty;
        pz.clear();
        //clear接口测试

        //cout << pzEmpty.exportPuzzle(FormatFullTable)<<endl << pz.exportPuzzle(FormatFullTable)<<endl;
        CPPUNIT_ASSERT(stricmp(pzEmpty.exportPuzzle(FormatFullTable),pz.exportPuzzle(FormatFullTable))==0);
        //全候选数表格导出测试
        CPPUNIT_ASSERT(stricmp(pzEmpty.exportPuzzle(FormatFullTable),pszEmpty)==0);

        //cout << pz.exportPuzzle(FormatFullTable)<<endl;
        pz.chainSetNumber(Point(1,1),1);
        pz.chainSetNumber(Point(9,9),9);
        //cout << pz.exportPuzzle(FormatFullTable)<<endl;
        //全候选数表格导出测试
        CPPUNIT_ASSERT(stricmp(pz.exportPuzzle(FormatFullTable),pszNotEmpty)==0);

	}

};
CPPUNIT_TEST_SUITE_REGISTRATION( BaseObjectTest );


#endif  // __BASEOBJECT_TEST_H
